﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ChessGameV2.AI
{
    public class Moves : List<Move>
    {
        public Moves()
        {
        }
        /// <summary>
        /// Sinh tap cac nuoc di chuyen hop le
        /// </summary>
        /// <param name="pColor">Mau quan co</param>
        /// <param name="board">Trang thai ban co</param>
        public Moves(int pColor, int[] board)
        {
            for (int i = 21; i < 99; i++)
            {
                if (board[i] % 100 / 10 == pColor)	//check color
                {
                    switch (board[i] % 10)
                    {
                        case 1: 
                            Pawn(i, pColor, board);
                            break;
                        case 2: 
                            Knight(i, pColor, board);
                            break;
                        case 5: 
                            Queen(i, pColor, board);
                            break;
                        case 3: 
                            Bishop(i, pColor, board);
                            break;
                        case 4: 
                            Rook(i, pColor, board);
                            break;
                        case 6:
                            if ((board [i] / 100 == 1) && (! isCheck(pColor,board)))
					        {
                                CastleKingSide(i,pColor,board);
                                CastleQueenSide(i, pColor, board);
                            }
                            King(i, pColor, board);
                            break;
                    }
                }
                if (i % 10 == 8)
                    i += 2;
            }
        }
        /// <summary>
        /// Sinh tap cac nuoc di hop le cho quan tot
        /// </summary>
        /// <param name="pColor"></param>
        /// <param name="board"></param>
        private void Pawn(int i, int PColor, int[] board)
        {
            if (PColor == 1)
            {
                if (board[i - 10] == 0)
                    simulize(i, i - 10, PColor, board, MoveType.Standard);
                if (board[i - 9] % 100 / 10 == 2)
                    simulize(i, i - 9, PColor, board, MoveType.Standard);
                if (board[i - 11] % 100 / 10 == 2)
                    simulize(i, i - 11, PColor, board, MoveType.Standard);
                if ((i > 80) && ((board[i - 10] == 0) && (board[i - 20] == 0)))
                    simulize(i, i - 20, PColor, board, MoveType.Standard);
            }
            else
            {
                if (board[i + 10] == 0)
                    simulize(i, i + 10, PColor, board, MoveType.Standard);
                if (board[i + 9] % 100 / 10 == 1)
                    simulize(i, i + 9, PColor, board, MoveType.Standard);
                if (board[i + 11] % 100 / 10 == 1)
                    simulize(i, i + 11, PColor, board, MoveType.Standard);
                if ((i < 39) && ((board[i + 10] == 0) && (board[i + 20] == 0)))
                    simulize(i, i + 20, PColor, board, MoveType.Standard);
            }
        }
        /// <summary>
        /// Sinh tap cac nuoc di hop le cho quan ma
        /// </summary>
        /// <param name="pColor"></param>
        /// <param name="board"></param>
        private void Knight(int i, int PColor, int[] board)
        {
            simulize(i, i + 12, PColor, board, MoveType.Standard);
            simulize(i, i - 12, PColor, board, MoveType.Standard);
            simulize(i, i + 21, PColor, board, MoveType.Standard);
            simulize(i, i - 21, PColor, board, MoveType.Standard);
            simulize(i, i + 19, PColor, board, MoveType.Standard);
            simulize(i, i - 19, PColor, board, MoveType.Standard);
            simulize(i, i + 8, PColor, board, MoveType.Standard);
            simulize(i, i - 8, PColor, board, MoveType.Standard);
        }
        /// <summary>
        /// Sinh tap cac nuoc di hop le cho quan hau
        /// </summary>
        /// <param name="pColor"></param>
        /// <param name="board"></param>
        private void Queen(int i, int PColor, int[] board)
        {
            multisimulize(i, -9, PColor, board);
            multisimulize(i, -11, PColor, board);
            multisimulize(i, +9, PColor, board);
            multisimulize(i, +11, PColor, board);

            multisimulize(i, -10, PColor, board);
            multisimulize(i, +10, PColor, board);
            multisimulize(i, -1, PColor, board);
            multisimulize(i, +1, PColor, board);
            return;
        }
        /// <summary>
        /// Sinh tap cac nuoc di hop le cho quan tuong
        /// </summary>
        /// <param name="pColor"></param>
        /// <param name="board"></param>
        private void Bishop(int i, int PColor, int[] board)
        {
            multisimulize(i, -9, PColor, board);
            multisimulize(i, -11, PColor, board);
            multisimulize(i, +9, PColor, board);
            multisimulize(i, +11, PColor, board);
        }
        /// <summary>
        /// Sinh tap cac nuoc di hop le cho quan Xe
        /// </summary>
        /// <param name="pColor"></param>
        /// <param name="board"></param>
        private void Rook(int i, int PColor, int[] board)
        {
            multisimulize(i, -10, PColor, board);
            multisimulize(i, +10, PColor, board);
            multisimulize(i, -1, PColor, board);
            multisimulize(i, +1, PColor, board);
        }
        /// <summary>
        /// Sinh tap cac nuoc di hop le cho quan Tuong
        /// </summary>
        /// <param name="pColor"></param>
        /// <param name="board"></param>
        private void King(int i, int PColor, int[] board)
        {
            simulize(i, i + 1, PColor, board, MoveType.Standard);
            simulize(i, i - 1, PColor, board, MoveType.Standard);
            simulize(i, i + 10, PColor, board, MoveType.Standard);
            simulize(i, i - 10, PColor, board, MoveType.Standard);
            simulize(i, i + 9, PColor, board, MoveType.Standard);
            simulize(i, i - 9, PColor, board, MoveType.Standard);
            simulize(i, i + 11, PColor, board, MoveType.Standard);
            simulize(i, i - 11, PColor, board, MoveType.Standard);
        }
        /// <summary>
        /// Sinh nuoc di nhap thanh xa
        /// </summary>
        /// <param name="pColor"></param>
        /// <param name="board"></param>
        private void CastleKingSide(int i, int pColor, int[] board)
        {
            if (((board[i + 1] == 0) && (board[i + 2] == 0)) && (board[i + 3] / 100 == 1))
            {	//little casteling				
                board[i + 1] = board[i] % 100;
                board[i] = 0;

                if (!isCheck( pColor , board ))
                {
                    //king back
                    board[i] = board[i + 1];
                    simulize(i, i + 2, pColor, board, MoveType.CastleKingSide);
                    return;
                }
                //rebuild original position
                board[i] = board[i + 1] + 100;
                board[i + 1] = 0;
                
            }
        }
        /// <summary>
        /// Sinh nuoc di nhap thanh gan
        /// </summary>
        /// <param name="pColor"></param>
        /// <param name="board"></param>
        private void CastleQueenSide(int i, int pColor, int[] board)
        {
            if (((board[i - 1] == 0) && (board[i - 2] == 0)) && ((board[i - 3] == 0) && (board[i - 4] / 100 == 1)))
            {	//big casteling
                board[i - 1] = board[i] % 100;
                board[i] = 0;

                if (!isCheck(pColor, board))
                {
                    //king back
                    board[i] = board[i - 1];
                    simulize(i, i - 2, pColor, board, MoveType.CastleQueenSide);
                    return;
                }
                //rebuild original position
                board[i] = board[i - 1] + 100;
                board[i - 1] = 0;
            }
        }
        /// <summary>
        /// Sinh mot buoc di chuyen hop le
        /// </summary>
        /// <param name="start">Vi tri can chuyen</param>
        /// <param name="to">Vi tri chuyen toi</param>
        /// <param name="PColor">Mau quan co</param>
        /// <param name="board">Ban co</param>
        private void simulize(int start, int to, int PColor, int[] board, MoveType _mt)
        {
            if (board[to] == 99 || board[to] % 100 / 10 == PColor)
                return;
            Move _test = new Move(start, to, PColor, board, _mt);
            _test.ExecuteMove(board);
            if(!isCheck(PColor,board))
                    this.Add(_test);
            _test.undo(board);
        }
        /// <summary>
        /// Sinh cac nuoc di chuyen cheo
        /// </summary>
        /// <param name="start"></param>
        /// <param name="inc"></param>
        /// <param name="PColor"></param>
        /// <param name="board"></param>
        private void multisimulize(int start, int inc, int PColor, int[] board)
        {
            int to = start;
            //khi vi tri cua quan co duoc chon con o trong ban co
            //va vi tri do o trong ban co.
            while ((board[to + inc] != 99))
            {
                to += inc;
                //chuyen vi tri cua quan dc chon len 
                if (board[to] != 0)
                {
                    simulize(start, to, PColor, board, MoveType.Standard);
                    return;
                }

                simulize(start, to, PColor, board, MoveType.Standard);
            }
            simulize(start, to, PColor, board, MoveType.Standard);
        }
        /// <summary>
        /// Ham kiem tra trang thai ban co co chieu tuong hay k?
        /// </summary>
        /// <param name="color"></param>
        /// <param name="board"></param>
        /// <returns></returns>
        public bool isCheck(int color, int[] board)
        {
            int king = 0;
            //tim vua
            for (int i = 21; i < 99; i++)
            {
                if ((board[i] % 100 / 10 == color) && (board[i] % 10 == 6))
                {
                    king = i;
                    break;
                }

                if (i % 10 == 8)
                    i += 2;
            }
            //knight
            if ((board[king - 21] % 10 == 2) && (board[king - 21] % 100 / 10 != color))
                return true;
            if ((board[king + 21] % 10 == 2) && (board[king + 21] % 100 / 10 != color))
                return true;
            if ((board[king - 19] % 10 == 2) && (board[king - 19] % 100 / 10 != color))
                return true;
            if ((board[king + 19] % 10 == 2) && (board[king + 19] % 100 / 10 != color))
                return true;
            if ((board[king - 8] % 10 == 2) && (board[king - 8] % 100 / 10 != color))
                return true;
            if ((board[king + 8] % 10 == 2) && (board[king + 8] % 100 / 10 != color))
                return true;
            if ((board[king - 12] % 10 == 2) && (board[king - 12] % 100 / 10 != color))
                return true;
            if ((board[king + 12] % 10 == 2) && (board[king + 12] % 100 / 10 != color))
                return true;

            //ishop
            int j = king;
            while (board[j - 9] != 99)
            {
                j -= 9;
                if (board[j] % 100 / 10 == color)
                    break;
                if (board[j] == 0)
                    continue;
                if ((board[j] % 10 == 3) || (board[j] % 10 == 5))
                    return true;
                else
                    break;
            }

            j = king;
            while (board[j + 9] != 99)
            {
                j += 9;
                if (board[j] % 100 / 10 == color)
                    break;
                if (board[j] == 0)
                    continue;
                if ((board[j] % 10 == 3) || (board[j] % 10 == 5))
                    return true;
                else
                    break;
            }

            j = king;
            while (board[j - 11] != 99)
            {
                j -= 11;
                if (board[j] % 100 / 10 == color)
                    break;
                if (board[j] == 0)
                    continue;
                if ((board[j] % 10 == 3) || (board[j] % 10 == 5))
                    return true;
                else
                    break;
            }

            j = king;
            while (board[j + 11] != 99)
            {
                j += 11;
                if (board[j] % 100 / 10 == color)
                    break;
                if (board[j] == 0)
                    continue;
                if ((board[j] % 10 == 3) || (board[j] % 10 == 5))
                    return true;
                else
                    break;
            }

            //rook
            j = king;
            while (board[j - 10] != 99)
            {
                j -= 10;
                if (board[j] % 100 / 10 == color)
                    break;
                if (board[j] == 0)
                    continue;
                if ((board[j] % 10 == 4) || (board[j] % 10 == 5))
                    return true;
                else
                    break;
            }
            j = king;
            while (board[j + 10] != 99)
            {
                j += 10;
                if (board[j] % 100 / 10 == color)
                    break;
                if (board[j] == 0)
                    continue;
                if ((board[j] % 10 == 4) || (board[j] % 10 == 5))
                    return true;
                else
                    break;
            }
            j = king;
            while (board[j - 1] != 99)
            {
                j -= 1;
                if (board[j] % 100 / 10 == color)
                    break;
                if (board[j] == 0)
                    continue;
                if ((board[j] % 10 == 4) || (board[j] % 10 == 5))
                    return true;
                else
                    break;
            }
            j = king;
            while (board[j + 1] != 99)
            {
                j += 1;
                if (board[j] % 100 / 10 == color)
                    break;
                if (board[j] == 0)
                    continue;
                if ((board[j] % 10 == 4) || (board[j] % 10 == 5))
                    return true;
                else
                    break;
            }

            //pawn
            if (color == 1)
            {
                if ((board[king - 11] % 10 == 1) && (board[king - 11] % 100 / 10 == 2))
                    return true;
                if ((board[king - 9] % 10 == 1) && (board[king - 9] % 100 / 10 == 2))
                    return true;
            }
            else
            {
                if ((board[king + 11] % 10 == 1) && (board[king + 11] % 100 / 10 == 1))
                    return true;
                if ((board[king + 9] % 10 == 1) && (board[king + 9] % 100 / 10 == 1))
                    return true;
            }

            //king
            if (board[king + 1] % 10 == 6)
                return true;
            if (board[king - 1] % 10 == 6)
                return true;
            if (board[king + 10] % 10 == 6)
                return true;
            if (board[king - 10] % 10 == 6)
                return true;
            if (board[king + 11] % 10 == 6)
                return true;
            if (board[king - 11] % 10 == 6)
                return true;
            if (board[king + 9] % 10 == 6)
                return true;
            if (board[king - 9] % 10 == 6)
                return true;
            return false;
        }
    }
}
